﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PostSharp.Laos;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace EditableBusinessObjects.Postsharp.Public
{
    /// <summary>
    /// rewrites field access to go to the appropriate dictionary of the
    /// editableBusinessObject implementation
    /// </summary>
    [Serializable]
    public class FieldInterceptionAspect : OnFieldAccessAspect
    {
        #region fields and properties
        /// <summary>
        /// cache of the fieldname
        /// </summary>
        string fieldName;
        /// <summary>
        /// Gets the name of the field.
        /// </summary>
        /// <value>The name of the field.</value>
        /// <remarks>was cached during compilation</remarks>
        public string FieldName { get { return fieldName; } }

        /// <summary>
        /// cache of the corresponding propertyname
        /// </summary>
        string propertyName;


        #endregion

        /// <summary>
        /// will cache some data about the field. Will be put into the resource file of our assembly by postsharp
        /// </summary>
        /// <param name="field"></param>
        /// <inheritdoc/>
        public override void CompileTimeInitialize(System.Reflection.FieldInfo field)
        {
            base.CompileTimeInitialize(field);

            fieldName = field.Name;

            // the editable businessobject needs to be accessed by propertyname
            Type declaring = field.DeclaringType;

            propertyName = (from p in declaring.GetProperties()
                                   where fieldName.EndsWith(p.Name, StringComparison.OrdinalIgnoreCase) ||
                                         fieldName.IndexOf("<" + p.Name + ">") == 0
                                   select p).Single().Name;
        }


        /// <summary>
        /// Just the normal way of returning the storedfield, but also notify
        /// our manager. It will be able to make a backup if needed
        /// </summary>
        /// <param name="eventArgs"></param>
        /// <inheritdoc/>
        public override void OnGetValue(FieldAccessEventArgs eventArgs)
        {
            IEditableBusinessObject editableObjectImpl = (IEditableBusinessObject)eventArgs.Instance;

            eventArgs.ExposedFieldValue = editableObjectImpl.GetValue(propertyName, eventArgs.StoredFieldValue);

        }

        /// <summary>
        /// Just the normal way of storing a field, but also notify
        /// our manager. It will be able to make a backup if needed
        /// </summary>
        /// <param name="eventArgs"></param>
        /// <inheritdoc/>
        public override void OnSetValue(FieldAccessEventArgs eventArgs)
        {
            IEditableBusinessObject editableObjectImpl = (IEditableBusinessObject)eventArgs.Instance;

            eventArgs.StoredFieldValue = editableObjectImpl.StoreValue(propertyName, eventArgs.ExposedFieldValue, eventArgs.StoredFieldValue);
        }
    }
}
